﻿using MQTTnet;
using MQTTnet.Protocol;
using System.Buffers;
using System.Net.WebSockets;
using System.Text;

namespace Zhaoxi.WebServer
{
    public class Program
    {
        private static IMqttClient mqttClient = null!;
        private static bool state = false;
        // 所有连接的websocket客户端
        private static List<WebSocket> webSockets = new List<WebSocket>();

        public async static Task Main(string[] args)
        {
            var builder = WebApplication.CreateBuilder(args);

            // Add services to the container.

            builder.Services.AddControllers();
            // Learn more about configuring Swagger/OpenAPI at https://aka.ms/aspnetcore/swashbuckle
            builder.Services.AddEndpointsApiExplorer();
            builder.Services.AddSwaggerGen();

            var app = builder.Build();

            // Configure the HTTP request pipeline.
            if (app.Environment.IsDevelopment())
            {
                app.UseSwagger();
                app.UseSwaggerUI();
            }

            // 连接到MQTT服务器(初始化MQTT客户端)
            #region 连接到MQTT服务器
            MqttClientFactory mqttFactory = new MqttClientFactory();
            mqttClient = mqttFactory.CreateMqttClient();
            MqttClientOptions mqttClientOptions = new MqttClientOptionsBuilder()
                .WithClientId(Guid.NewGuid().ToString())
                .WithTcpServer("127.0.0.1", 1883)
                .WithCredentials("admin", "123456")
                .WithCleanSession(false)
                .Build();

            mqttClient.ConnectedAsync += e =>
            {
                state = true;

                mqttClient.SubscribeAsync("d/#");
                return Task.CompletedTask;
            };

            // MQTT客户端异步连接到服务器
            MqttClientConnectResult connectResult = await mqttClient.ConnectAsync(mqttClientOptions, CancellationToken.None);
            //Console.WriteLine(($"连接状态:{connectResult.ResultCode.ToString()}"));
            #endregion

            #region 接收订阅主题的消息
            try
            {
                mqttClient.ApplicationMessageReceivedAsync += e =>
                {

                    ReadOnlySequence<byte> msgArray = e.ApplicationMessage.Payload;
                    var msg = Encoding.UTF8.GetString(msgArray);
                    //var msg = BitConverter.ToString(msgArray.ToArray()).Replace("-"," "); // 转换为十六进制字符串

                    Console.WriteLine($">>> 收到消息: {msg},来自客户端:{e.ClientId},主题:{e.ApplicationMessage.Topic}");


                    // 接收当前订阅主题下的所有消息
                    // 这个消息需要通过WebSocket进行转发
                    foreach (var item in webSockets)
                    {
                        // 将所有连接进来的Web前端进行消息分发
                        item.SendAsync(new ArraySegment<byte>(e.ApplicationMessage.Payload.ToArray(), 0, (int)e.ApplicationMessage.Payload.Length),
                            WebSocketMessageType.Text,   // 发送的是文本
                            true,     // 当前消息是否发送完成了，是否有后续消息。（缓冲区中的数据是否为消息的最后一部分）
                            CancellationToken.None);

                    }

                    return Task.CompletedTask;
                };
            }
            catch (Exception exception)
            {
                Console.WriteLine(exception.Message);
            }
            #endregion

            // 开启 WebSocket 功能的中间件
            app.UseWebSockets();
            // 处理 WebSocket 请求的中间件
            app.Use(async (context, next) =>
            {
                // 此处指定了请求 URL 的Path 为 /ws,即完整URL为：ws://localhost:5000/ws
                if (context.Request.Path == "/ws")
                {
                    // 如果是 WebSocket 请求
                    if (context.WebSockets.IsWebSocketRequest)
                    {
                        // 等待客户端连接
                        WebSocket wsClient = await context.WebSockets.AcceptWebSocketAsync();
                        Console.WriteLine($"WebSocket connected");
                        webSockets.Add(wsClient);
                        // 处理连接
                        await ReceiveHander(wsClient);

                        //// 这里可以开始接收和发送消息
                        //var buffer = new byte[1024 * 4];
                        //var result = await webSocket.ReceiveAsync(new ArraySegment<byte>(buffer), CancellationToken.None);
                        //while (!result.CloseStatus.HasValue)
                        //{
                        //    // Echo the message back to the client
                        //    await webSocket.SendAsync(new ArraySegment<byte>(buffer, 0, result.Count), result.MessageType, result.EndOfMessage, CancellationToken.None);
                        //    result = await webSocket.ReceiveAsync(new ArraySegment<byte>(buffer), CancellationToken.None);
                        //}
                        //await webSocket.CloseAsync(result.CloseStatus.Value, result.CloseStatusDescription, CancellationToken.None);
                        //Console.WriteLine("WebSocket disconnected");
                    }
                    else
                    {
                        // 如果 ws://localhost:5000/ws 不是一个合法的 WebSocket 请求，则返回 400 状态码
                        context.Response.StatusCode = 400;
                    }
                }
                else
                {
                    // 如果请求 URL 的 Path 部分不是 /ws，则发给下一个中间件处理
                    await next();
                }
            });

            app.UseAuthorization();


            app.MapControllers();

            app.Run();
        }



        private static async Task ReceiveHander(WebSocket wsClient)
        {
            // 接收缓冲
            byte[] buffer = new byte[1024];

            // 等待接收
            WebSocketReceiveResult result = await wsClient.ReceiveAsync(new ArraySegment<byte>(buffer), CancellationToken.None);

            // 接收消息主循环
            // !result.CloseStatus.HasValue 用来判断客户端是否仍然处于连接状态
            while (!result.CloseStatus.HasValue)
            {
                // 只取实际接收到的字节数(需要创建一个新的字节数组)
                byte[] actualBytes = new byte[result.Count];
                Array.Copy(buffer, actualBytes, result.Count);

                string msg = Encoding.UTF8.GetString(actualBytes);
                // 更优方案（复用缓冲区，避免频繁创建新的字节数组）最佳：只转换读取的实际的字节数量
                //string msg = Encoding.UTF8.GetString(buffer,0,result.Count);
                Console.WriteLine($"Received:{msg}");

                // 数据格式的设计  "主题|消息"
                // msg.Split('|', 2) 中的第二个参数 2 是一个 count 参数，它的意思是： 最多将字符串拆分成 2 个部分。
                // string msg = "topic|hello|world|goodbye";
                // msg.Split('|', 2) 之后结果是:
                // parts[0] = "topic"
                // parts[1] = "hello|world|goodbye"  // 剩下的全部作为一个整体
                string[] temp = msg.Split('|', 2);

                MqttApplicationMessage messageApplication = new MqttApplicationMessageBuilder()
               .WithTopic(temp[0])
               .WithPayload(temp[1])  // 直接发送字符串    //.WithPayload(bytes)  // 发送字节数组
               .WithQualityOfServiceLevel(MqttQualityOfServiceLevel.AtMostOnce)
               .WithRetainFlag(false)
               .Build();

                await mqttClient.PublishAsync(messageApplication, CancellationToken.None);

                // 等待接收下一次消息
                buffer = new byte[1024];
                result = await wsClient.ReceiveAsync(new ArraySegment<byte>(buffer), CancellationToken.None);
            }
        }



    }
}
